package com.gitee.hermer.boot.jee.commons.reflect;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import org.apache.commons.lang.reflect.ConstructorUtils;
import org.springframework.aop.framework.AdvisedSupport;
import org.springframework.aop.framework.AopProxy;
import org.springframework.aop.support.AopUtils;

import com.gitee.hermer.boot.jee.commons.collection.CollectionUtils;
import com.gitee.hermer.boot.jee.commons.exception.ErrorCode;
import com.gitee.hermer.boot.jee.commons.exception.PaiUException;
import com.gitee.hermer.boot.jee.commons.log.Logger;
import com.gitee.hermer.boot.jee.commons.utils.StringUtils;
import com.gitee.hermer.boot.jee.commons.verify.Assert;


public class ClassUtils {


	private final static Logger logger = Logger.getLogger(ClassUtils.class);

	/** ".class"文件扩展名 */
	public static final String CLASSPATH_PREFIX = "classpath:";

	/** class包分割符: <code>"&#x2e;"</code> */
	public static final String PACKAGE_SEPARATOR = String.valueOf('.');

	/** Suffix for class, e.g. class java.lang.String */
	public static final String CLASS_TYPE_TOSTRING_SUFFIX = "class ";

	/** Suffix for class, e.g. interface java.util.List */
	public static final String INTERFACE_TYPE_TOSTRING_SUFFIX = "interface ";

	/** Suffix for array class names: "[]" */
	public static final String ARRAY_SUFFIX = "[]";

	/** Prefix for internal array class names: "[" */
	private static final String INTERNAL_ARRAY_PREFIX = "[";

	/** Prefix for internal non-primitive array class names: "[L" */
	private static final String NON_PRIMITIVE_ARRAY_PREFIX = "[L";

	/** The inner class separator character '$' */
	private static final char INNER_CLASS_SEPARATOR = '$';

	/** The CGLIB class separator character "$$" */
	public static final String CGLIB_CLASS_SEPARATOR = "$$";

	/** The ".class" file suffix */
	public static final String CLASS_FILE_SUFFIX = ".class";

	/** Jar文件扩展名 */
	private static final String JAR_FILE_EXT = ".jar";

	/** 在Jar中的路径jar的扩展名形式 */
	private static final String JAR_PATH_EXT = ".jar!";

	/** 当Path为文件形式时, path会加入一个表示文件的前缀 */
	private static final String PATH_FILE_PRE = "file:";

	/** 扫描Class文件时空的过滤器，表示不过滤 */
	private static final ClassFilter NULL_CLASS_FILTER = null;

	/**
	 * 基本类型名字的包装类型到原始类型的映射 for example: Integer.class -> int.class.
	 */
	private static final Map<Class<?>, Class<?>> primitiveWrapperTypeMap = new HashMap<Class<?>, Class<?>>(8);

	/**
	 * 基本类型名字的原始类型到包装类型的映射 for example: int.class -> Integer.class.
	 */
	private static final Map<Class<?>, Class<?>> primitiveTypeToWrapperMap = new HashMap<Class<?>, Class<?>>(8);

	/**
	 * 基本类型名字的String类型到Class<?>类型的映射 for example: "int" -> "int.class".
	 */
	private static final Map<String, Class<?>> primitiveTypeNameMap = new HashMap<String, Class<?>>(32);

	/**
	 * Map with common "java.lang" class name as key and corresponding Class as value. Primarily for efficient deserialization of remote invocations.
	 */
	private static final Map<String, Class<?>> commonClassCache = new HashMap<String, Class<?>>(32);

	static {
		primitiveWrapperTypeMap.put(Boolean.class, boolean.class);
		primitiveWrapperTypeMap.put(Byte.class, byte.class);
		primitiveWrapperTypeMap.put(Character.class, char.class);
		primitiveWrapperTypeMap.put(Double.class, double.class);
		primitiveWrapperTypeMap.put(Float.class, float.class);
		primitiveWrapperTypeMap.put(Integer.class, int.class);
		primitiveWrapperTypeMap.put(Long.class, long.class);
		primitiveWrapperTypeMap.put(Short.class, short.class);

		for (Map.Entry<Class<?>, Class<?>> entry : primitiveWrapperTypeMap.entrySet()) {
			primitiveTypeToWrapperMap.put(entry.getValue(), entry.getKey());
			registerCommonClasses(entry.getKey());
		}

		Set<Class<?>> primitiveTypes = new HashSet<Class<?>>(32);
		primitiveTypes.addAll(primitiveWrapperTypeMap.values());
		primitiveTypes
		.addAll(Arrays.asList(new Class<?>[] { boolean[].class, byte[].class, char[].class, double[].class, float[].class, int[].class, long[].class, short[].class }));
		primitiveTypes.add(void.class);
		for (Class<?> primitiveType : primitiveTypes) {
			primitiveTypeNameMap.put(primitiveType.getName(), primitiveType);
		}

		registerCommonClasses(Boolean[].class, Byte[].class, Character[].class, Double[].class, Float[].class, Integer[].class, Long[].class, Short[].class);
		registerCommonClasses(Number.class, Number[].class, String.class, String[].class, Object.class, Object[].class, Class.class, Class[].class);
		registerCommonClasses(Throwable.class, Exception.class, RuntimeException.class, Error.class, StackTraceElement.class, StackTraceElement[].class);
	}

	/** 
	 * 文件过滤器，过滤掉不需要的文件<br>
	 * 只保留Class文件、目录和Jar
	 */
	private static FileFilter fileFilter = new FileFilter(){
		@Override
		public boolean accept(File pathname) {
			return isClass(pathname.getName()) || pathname.isDirectory() || isJarFile(pathname);
		}
	};

	public static <T> T getTargetProxy(Object proxy) throws PaiUException{
		if (!AopUtils.isAopProxy(proxy)) {
			return (T) proxy;
		}else{
			try{
				if (AopUtils.isJdkDynamicProxy(proxy)) {
					Field h = proxy.getClass().getSuperclass().getDeclaredField("h");  
					h.setAccessible(true);  
					AopProxy aopProxy = (AopProxy) h.get(proxy);  
					Field advised = aopProxy.getClass().getDeclaredField("advised");  
					advised.setAccessible(true);  
					return (T)((AdvisedSupport)advised.get(aopProxy)).getTargetSource().getTarget();   
				} else { //cglib
					Field h = proxy.getClass().getDeclaredField("CGLIB$CALLBACK_0");
					h.setAccessible(true);
					Object dynamicAdvisedInterceptor = h.get(proxy);
					Field advised = dynamicAdvisedInterceptor.getClass().getDeclaredField("advised");
					advised.setAccessible(true);
					return (T)((AdvisedSupport)advised.get(dynamicAdvisedInterceptor)).getTargetSource().getTarget();
				}
			}catch (Exception e) {
				throw new PaiUException(ErrorCode.SYSTEM_ERROR, e,"获取Proxy对象失败："+proxy);
			}
		}
	}

	/**
	 * 加载类并创建class实例
	 * @param <T>
	 * @param className
	 * @param parameters
	 * @param parameterTypes
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static <T> T createInstance(String className, Object[] parameters, Class<?>[] parameterTypes) {
		Class<?> clazz = null;
		T bean = null;
		try {
			clazz = org.apache.commons.lang.ClassUtils.getClass(className);
			bean = (T) ConstructorUtils.invokeConstructor(clazz, parameters, parameterTypes);
		} catch (ClassNotFoundException e) {
			////// Assert.error("找不到类[" + className + "]", e);
		} catch (NoSuchMethodException e) {
			// LOGGER.error("[" + clazz.getName() + "]中没有找到指定的构造方法", e);
		} catch (IllegalAccessException e) {
			// LOGGER.error("无法访问[" + clazz.getName() + "]的构造方法", e);
		} catch (InvocationTargetException e) {
			// LOGGER.error("无法访问[" + clazz.getName() + "]的构造方法", e);
		} catch (InstantiationException e) {
			// LOGGER.error("无法实例化[" + clazz.getName() + "]", e);
		}

		return bean;
	}

	/**
	 * 返回实例对应的用户实际定义的Class，（CGLIB生成的类是用户定义类的子类）
	 * @param instance
	 * @return
	 */
	public static Class<?> getUserClass(Object instance) {
		// Assert.notNull(instance, "实例不能为空");
		return getUserClass(instance.getClass());
	}

	/**
	 * 返回用户实际定义的Class，（CGLIB生成的类是用户定义类的子类）
	 * @param clazz
	 * @return
	 */
	public static Class<?> getUserClass(Class<?> clazz) {
		if (clazz != null && clazz.getName().contains(CGLIB_CLASS_SEPARATOR)) {
			Class<?> superClass = clazz.getSuperclass();
			if (superClass != null && !Object.class.equals(superClass)) {
				return superClass;
			}
		}
		return clazz;
	}

	/**
	 * 通过class获取对应的.class文件名。比如java.lang.String类会返回"String.class"
	 * @param clazz
	 * @return
	 */
	public static String getClassFileName(Class<?> clazz) {
		//// Assert.notNull(clazz, "Class不能为空");
		String className = clazz.getName();
		int lastDotIndex = className.lastIndexOf(PACKAGE_SEPARATOR);
		return className.substring(lastDotIndex + 1) + CLASS_FILE_SUFFIX;
	}
	public static String getClassName(Class<?> clazz) {
		//// Assert.notNull(clazz, "Class不能为空");
		String className = clazz.getName();
		int lastDotIndex = className.lastIndexOf(PACKAGE_SEPARATOR);
		return className.substring(lastDotIndex + 1);
	}

	/**
	 * <p>注册一些常用的公共的class到缓存中去</p>
	 * @param commonClasses
	 */
	private static void registerCommonClasses(Class<?>... commonClasses) {
		for (Class<?> clazz : commonClasses) {
			commonClassCache.put(clazz.getName(), clazz);
		}
	}

	/**
	 * <p>
	 * 获取系统默认的ClassLoader
	 * </p>
	 * 
	 * @return
	 */
	public static ClassLoader getDefaultClassLoader() {
		ClassLoader cl = null;
		try {
			cl = Thread.currentThread().getContextClassLoader();
		} catch (Throwable ex) {
			// Cannot access thread context ClassLoader - falling back to system class loader...
		}
		if (cl == null) {
			// No thread context class loader -> use class loader of this class.
			cl = ClassUtils.class.getClassLoader();
		}
		return cl;
	}

	/**
	 * @return 当前线程的class loader
	 */
	public static ClassLoader getContextClassLoader() {
		return Thread.currentThread().getContextClassLoader();
	}

	/**
	 * 获得class loader<br>
	 * 若当前线程class loader不存在，取当前类的class loader
	 * 
	 * @return 类加载器
	 */
	public static ClassLoader getClassLoader() {
		ClassLoader classLoader = getContextClassLoader();
		if (classLoader == null) {
			classLoader = ClassUtils.class.getClassLoader();
		}
		return classLoader;
	}


	/**
	 * <p>
	 * 根据字符串形式的class表示形式获取其Class<?>类型
	 * </p>
	 * 
	 * <pre>
	 * for example: "int"					-> 		Integer.class
	 * 				"java.util.Date"		->		Date.class
	 * 				"class java.util.Date"	->		Date.class
	 * 				"interface java.util.List"	->	List.class
	 * 				"java.lang.String[]"	->		String[].class
	 * 				"[Ljava.lang.String;"	->		String[].class
	 * 				"[[Ljava.lang.String;"	->		String[][].class
	 * 				"java.lang.Thread.State"->		Thread.State.class
	 * 				"java.lang.Thread$State"->		Thread.State.class
	 * </pre>
	 * 
	 * @param name
	 * @param classLoader
	 * @return
	 * @throws ClassNotFoundException
	 * @throws LinkageError
	 */
	public static Class<?> forName(String name, ClassLoader classLoader) throws ClassNotFoundException, LinkageError {
		//// Assert.notNull(name, "Name must not be null");

		Class<?> clazz = resolvePrimitiveClassName(name);
		if (clazz == null) {
			clazz = commonClassCache.get(name);
		}
		if (clazz != null) {
			return clazz;
		}

		if (name.startsWith(CLASS_TYPE_TOSTRING_SUFFIX)) { // strip start "class "
			name = name.substring(CLASS_TYPE_TOSTRING_SUFFIX.length()).trim();
		} else if (name.startsWith(INTERFACE_TYPE_TOSTRING_SUFFIX)) { // strip start "interface "
			name = name.substring(INTERFACE_TYPE_TOSTRING_SUFFIX.length()).trim();
		}

		// "java.lang.String[]" style arrays
		if (name.endsWith(ARRAY_SUFFIX)) {
			String elementClassName = name.substring(0, name.length() - ARRAY_SUFFIX.length());
			Class<?> elementClass = forName(elementClassName, classLoader);
			return Array.newInstance(elementClass, 0).getClass();
		}

		// "[Ljava.lang.String;" style arrays
		if (name.startsWith(NON_PRIMITIVE_ARRAY_PREFIX) && name.endsWith(";")) {
			String elementName = name.substring(NON_PRIMITIVE_ARRAY_PREFIX.length(), name.length() - 1);
			Class<?> elementClass = forName(elementName, classLoader);
			return Array.newInstance(elementClass, 0).getClass();
		}

		// "[[I" or "[[Ljava.lang.String;" style arrays
		if (name.startsWith(INTERNAL_ARRAY_PREFIX)) {
			String elementName = name.substring(INTERNAL_ARRAY_PREFIX.length());
			Class<?> elementClass = forName(elementName, classLoader);
			return Array.newInstance(elementClass, 0).getClass();
		}

		ClassLoader classLoaderToUse = classLoader;
		if (classLoaderToUse == null) {
			classLoaderToUse = getDefaultClassLoader();
		}
		try {
			return classLoaderToUse.loadClass(name);
		} catch (ClassNotFoundException ex) {
			int lastDotIndex = name.lastIndexOf('.');
			if (lastDotIndex != -1) {
				String innerClassName = name.substring(0, lastDotIndex) + '$' + name.substring(lastDotIndex + 1);
				try {
					return classLoaderToUse.loadClass(innerClassName);
				} catch (ClassNotFoundException ex2) {
					// swallow - let original exception get through
				}
			}
			throw ex;
		}
	}
	/**
	 * 
	 * @Title: 
	 * @Description: 获取泛型类实际参数
	 * @param: @param clz
	 * @param: @param index
	 * @param: @return
	 * @param: @throws PaiUException       
	 * @author:  涂孟超
	 * @date: 2017年10月9日 上午10:20:19
	 * @throws
	 */
	public static Class<?> getSuperClassActualTypeArguments(Class clz,Integer index) throws PaiUException{
		Assert.notNull(index);
		Assert.notNull(clz);
		ParameterizedType pt = (ParameterizedType) clz.getGenericSuperclass();
		return (Class) pt.getActualTypeArguments()[index];
	}
	

	/**
	 * <p>
	 * 根据基本类型的String形式得到其Class<?>类型
	 * </p>
	 * 
	 * <pre>
	 * for example: "int" -> int.class
	 * </pre>
	 * 
	 * @param name
	 * @return
	 */
	public static Class<?> resolvePrimitiveClassName(String name) {
		Class<?> result = null;
		// Most class names will be quite long, considering that they
		// SHOULD sit in a package, so a length check is worthwhile.
		if (name != null && name.length() <= 8) {
			// Could be a primitive - likely.
			result = primitiveTypeNameMap.get(name);
		}
		return result;
	}

	/**
	 * <p>
	 * 判断baseType是否是subType的父类或本身
	 * </p>
	 * 
	 * @param baseType
	 * @param subType
	 * @return
	 */
	public static boolean isAssignable(Class<?> baseType, Class<?> subType) {
		// Assert.notNull(baseType, "baseType must not be null");
		// Assert.notNull(subType, "subType must not be null");
		if (baseType.isAssignableFrom(subType)) {
			return true;
		}
		if (baseType.isPrimitive()) {
			Class<?> resolvedPrimitive = primitiveWrapperTypeMap.get(subType);
			if (resolvedPrimitive != null && baseType.equals(resolvedPrimitive)) {
				return true;
			}
		} else {
			Class<?> resolvedWrapper = primitiveTypeToWrapperMap.get(subType);
			if (resolvedWrapper != null && baseType.isAssignableFrom(resolvedWrapper)) {
				return true;
			}
		}
		return false;
	}

	/**
	 * <p>
	 * 判断baseType是否是subTypeValue对应类型的父类或本身
	 * </p>
	 * 
	 * @param baseType
	 * @param subTypeValue
	 * @return
	 */
	public static boolean isAssignableValue(Class<?> baseType, Object subTypeValue) {
		// Assert.notNull(baseType, "baseType must not be null");
		return (subTypeValue != null ? isAssignable(baseType, subTypeValue.getClass()) : !baseType.isPrimitive());
	}

	/**
	 * <p>
	 * 检测参数object是否是一个cglib的代理对象
	 * </p>
	 * 
	 * @param object
	 * @return
	 */
	public static boolean isCglibProxy(Object object) {
		return ClassUtils.isCglibProxyClass(object.getClass());
	}

	/**
	 * <p>
	 * 检测参数clazz是否是一个cglib的代理对象类型
	 * </p>
	 * 
	 * @param clazz
	 * @return
	 */
	public static boolean isCglibProxyClass(Class<?> clazz) {
		return (clazz != null && isCglibProxyClassName(clazz.getName()));
	}

	/**
	 * <p>
	 * 检测参数clazzName是否是一个cglib的代理对象类型
	 * </p>
	 * @param className
	 * @return
	 */
	public static boolean isCglibProxyClassName(String className) {
		return (className != null && className.contains(CGLIB_CLASS_SEPARATOR));
	}

	/**
	 * <p>
	 * 根据class获取package名字
	 * </p>
	 * @param clazz
	 * @return
	 */
	public static String getPackageName(Class<?> clazz) {
		// Assert.notNull(clazz, "Class must not be null");
		return getPackageName(clazz.getName());
	}

	/**
	 * <p>
	 * 根据类名获取package名字
	 * </p>
	 * 
	 * @param fqClassName
	 * @return
	 */
	public static String getPackageName(String fqClassName) {
		// Assert.notNull(fqClassName, "Class name must not be null");
		int lastDotIndex = fqClassName.lastIndexOf(PACKAGE_SEPARATOR);
		return (lastDotIndex != -1 ? fqClassName.substring(0, lastDotIndex) : "");
	}

	/**
	 * 是否有注解
	 *
	 * @param clazz a {@link java.lang.Class} object.
	 * @param annotationClass a {@link java.lang.Class} object.
	 * @return a boolean.
	 */
	public static boolean hasClassAnnotation(Class<?> clazz, Class<? extends Annotation> annotationClass) {
		return getClassAnnotation(clazz, annotationClass) != null;
	}

	/**
	 * 是否有注解
	 *
	 * @param clazz a {@link java.lang.Class} object.
	 * @param annotationClass a {@link java.lang.Class} object.
	 * @param fieldName a {@link java.lang.String} object.
	 * @throws cn.yicha.commons.exception.YichaException if any.
	 * @return a boolean.
	 */
	public static boolean hasFieldAnnotation(Class<?> clazz, Class<? extends Annotation> annotationClass, String fieldName) throws Exception {
		return getFieldAnnotation(clazz, annotationClass, fieldName) != null;
	}

	/**
	 * 是否有注解
	 *
	 * @param clazz a {@link java.lang.Class} object.
	 * @param annotationClass a {@link java.lang.Class} object.
	 * @param methodName a {@link java.lang.String} object.
	 * @param paramType a {@link java.lang.Class} object.
	 * @throws cn.yicha.commons.exception.YichaException if any.
	 * @return a boolean.
	 */
	public static boolean hasMethodAnnotation(Class<?> clazz, Class<? extends Annotation> annotationClass, String methodName, Class<?>... paramType) throws Exception {
		return getMethodAnnotation(clazz, annotationClass, methodName, paramType) != null;
	}

	/**
	 * 获取类注解
	 *
	 * @param clazz 类
	 * @param annotationClass 注解类
	 * @return a A object.
	 */
	public static <A extends Annotation> A getClassAnnotation(Class<?> clazz, Class<A> annotationClass) {
		return clazz.getAnnotation(annotationClass);
	}

	
	/**
	 * 根据注解获取类的对象属性
	 *
	 * @param clazz 类
	 * @param annotationClass 注解类
	 * @param fieldName 成员属性名
	 * @return a A object.
	 */
	public static <A extends Annotation> Field  getField(Class<?> clazz, Class<A> annotationClass) throws Exception {
		java.lang.reflect.Field[] fields = clazz.getDeclaredFields();
		for (Field field : fields) {
			if(getFieldAnnotation(clazz,annotationClass,field.getName()) != null){
				return field;
			}
		}
		return null;
	}
	
	
	/**
	 * 获取类成员注解
	 *
	 * @param clazz 类
	 * @param annotationClass 注解类
	 * @param fieldName 成员属性名
	 * @return a A object.
	 */
	public static <A extends Annotation> A getFieldAnnotation(Class<?> clazz, Class<A> annotationClass, String fieldName) throws Exception {
		try {
			Field field = clazz.getDeclaredField(fieldName);
			if (field == null) {
				throw new Exception("no such field[" + fieldName + "] in " + clazz.getCanonicalName());
			}
			return field.getAnnotation(annotationClass);
		} catch (SecurityException e) {
			e.printStackTrace();
			throw new Exception("access error: field[" + fieldName + "] in " + clazz.getCanonicalName(), e);
		} catch (NoSuchFieldException e) {
			e.printStackTrace();
			throw new Exception("no such field[" + fieldName + "] in " + clazz.getCanonicalName());
		}
	}

	/**
	 * 获取类方法上的注解
	 * @param clazz 类
	 * @param annotationClass 注解类
	 * @param methodName 方法名
	 * @param paramType 方法参数
	 * @return a A object.
	 */
	public static <A extends Annotation> A getMethodAnnotation(Class<?> clazz, Class<A> annotationClass, String methodName, Class<?>... paramType) throws Exception {
		try {
			Method method = clazz.getDeclaredMethod(methodName, paramType);
			if (method == null) {
				throw new Exception("access error: method[" + methodName + "] in " + clazz.getCanonicalName());
			}
			return method.getAnnotation(annotationClass);
		} catch (SecurityException e) {
			e.printStackTrace();
			throw new Exception("access error: method[" + methodName + "] in " + clazz.getCanonicalName(), e);
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
			throw new Exception("no such method[" + methodName + "] in " + clazz.getCanonicalName(), e);
		}
	}

	/**
	 * 从包package中获取所有的Class
	 * @param pagekageName 包名
	 * @param recursive 是否递归
	 * @return a {@link java.util.Set} object.
	 */
	public static Set<Class<?>> getClasses(String pagekageName, boolean recursive) {
		// 第一个class类的集合
		Set<Class<?>> classes = new LinkedHashSet<Class<?>>();
		// 获取包的名字 并进行替换
		String packageName = pagekageName;
		String packageDirName = packageName.replace('.', '/');
		// 定义一个枚举的集合 并进行循环来处理这个目录下的things
		Enumeration<URL> dirs;
		try {
			dirs = Thread.currentThread().getContextClassLoader().getResources(packageDirName);
			// 循环迭代下去
			while (dirs.hasMoreElements()) {
				// 获取下一个元素
				URL url = dirs.nextElement();
				// 得到协议的名称
				String protocol = url.getProtocol();
				// 如果是以文件的形式保存在服务器上
				if ("file".equals(protocol)) {
					// 获取包的物理路径
					String filePath = URLDecoder.decode(url.getFile(), "UTF-8");
					// 以文件的方式扫描整个包下的文件 并添加到集合中
					findAndAddClassesInPackageByFile(packageName, filePath, recursive, classes);
				} else if ("jar".equals(protocol)) {
					// 如果是jar包文件
					// 定义一个JarFile
					JarFile jar;
					try {
						// 获取jar
						jar = ((JarURLConnection) url.openConnection()).getJarFile();
						// 从此jar包 得到一个枚举类
						Enumeration<JarEntry> entries = jar.entries();
						// 同样的进行循环迭代
						while (entries.hasMoreElements()) {
							// 获取jar里的一个实体 可以是目录 和一些jar包里的其他文件 如META-INF等文件
							JarEntry entry = entries.nextElement();
							String name = entry.getName();
							// 如果是以/开头的
							if (name.charAt(0) == '/') {
								// 获取后面的字符串
								name = name.substring(1);
							}
							// 如果前半部分和定义的包名相同
							if (name.startsWith(packageDirName)) {
								int idx = name.lastIndexOf('/');
								// 如果以"/"结尾 是一个包
								if (idx != -1) {
									// 获取包名 把"/"替换成"."
									packageName = name.substring(0, idx).replace('/', '.');
								}
								// 如果可以迭代下去 并且是一个包
								if ((idx != -1) || recursive) {
									// 如果是一个.class文件 而且不是目录
									if (name.endsWith(".class") && !entry.isDirectory()) {
										// 去掉后面的".class" 获取真正的类名
										String className = name.substring(packageName.length() + 1, name.length() - 6);
										try {
											// 添加到classes
											classes.add(Class.forName(packageName + '.' + className));
										} catch (ClassNotFoundException e) {
											e.printStackTrace();
											// log
											// .error("添加用户自定义视图类错误 找不到此类的.class文件");
										}
									}
								}
							}
						}
					} catch (IOException e) {
						// logger.error("在扫描用户定义视图时从jar包获取文件出错");
						throw new RuntimeException(e);
					}
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		}

		return classes;
	}

	/**
	 * 以文件的形式来获取包下的所有Class
	 *
	 * @param packageName a {@link java.lang.String} object.
	 * @param packagePath a {@link java.lang.String} object.
	 * @param recursive a boolean.
	 * @param classes a {@link java.util.Set} object.
	 */
	public static void findAndAddClassesInPackageByFile(String packageName, String packagePath, final boolean recursive, Set<Class<?>> classes) {
		// 获取此包的目录 建立一个File
		File dir = new File(packagePath);
		// 如果不存在或者 也不是目录就直接返回
		if (!dir.exists() || !dir.isDirectory()) {
			// logger.warn("用户定义包名 " + packageName + " 下没有任何文件");
			return;
		}
		// 如果存在 就获取包下的所有文件 包括目录
		File[] dirfiles = dir.listFiles(new FileFilter() {
			// 自定义过滤规则 如果可以循环(包含子目录) 或则是以.class结尾的文件(编译好的java类文件)
			@Override
			public boolean accept(File file) {
				return (recursive && file.isDirectory()) || (file.getName().endsWith(".class"));
			}
		});
		// 循环所有文件
		for (File file : dirfiles) {
			// 如果是目录 则继续扫描
			if (file.isDirectory()) {
				findAndAddClassesInPackageByFile(packageName + "." + file.getName(), file.getAbsolutePath(), recursive, classes);
			} else {
				// 如果是java类文件 去掉后面的.class 只留下类名
				String className = file.getName().substring(0, file.getName().length() - 6);
				try {
					// 添加到集合中去
					classes.add(Class.forName(packageName + '.' + className));
				} catch (ClassNotFoundException e) {
					// logger.error("添加用户自定义视图类错误 找不到此类的.class文件");
					e.printStackTrace();
				}
			}
		}
	}

	/**
	 * <p>
	 * Description：给一个接口，返回这个接口同一个包下的所有实现类
	 * </p>
	 * @param c a {@link java.lang.Class} object.
	 * @return a {@link java.util.List} object.
	 */
	public static List<Class<?>> getAllClassByInterface(Class<?> c) {
		List<Class<?>> returnClassList = new ArrayList<Class<?>>(); // 返回结果
		// 如果不是一个接口，则不做处理
		if (!c.isInterface()) {
			return returnClassList;
		}
		String packageName = c.getPackage().getName(); // 获得当前的包名
		Set<Class<?>> allClass = getClasses(packageName, true); // 获得当前包下以及子包下的所有类
		// 判断是否是同一个接口
		for (Class<?> clazz : allClass) {
			if (c.isAssignableFrom(clazz)) { // 判断是不是一个接口
				if (!c.equals(clazz)) { // 本身不加进去
					returnClassList.add(clazz);
				}
			}
		}
		return returnClassList;
	}

	/**
	 * 扫面改包路径下所有class文件
	 * 
	 * @param packageName 包路径 com | com. | com.abs | com.abs.
	 * @return
	 */
	public static Set<Class<?>> scanPackage(String packageName) {
		logger.debug("Scan classes from package [{"+packageName+"}]...");
		return scanPackage(packageName, NULL_CLASS_FILTER);
	}

	/**
	 * 扫面包路径下满足class过滤器条件的所有class文件，</br> 
	 * 如果包路径为 com.abs + A.class 但是输入 abs会产生classNotFoundException</br>
	 * 因为className 应该为 com.abs.A 现在却成为abs.A,此工具类对该异常进行忽略处理,有可能是一个不完善的地方，以后需要进行修改</br>
	 * 
	 * @param packageName 包路径 com | com. | com.abs | com.abs.
	 * @param classFilter class过滤器，过滤掉不需要的class
	 * @return
	 */
	public static Set<Class<?>> scanPackage(String packageName, ClassFilter classFilter) {
		if(StringUtils.isBlank(packageName)) throw new NullPointerException("packageName can't be blank!");
		packageName = getWellFormedPackageName(packageName);

		final Set<Class<?>> classes = new HashSet<Class<?>>();
		for (String classPath : getClassPaths(packageName)) {
			logger.debug("Scan classpath: [{"+classPath+"}]");
			// 填充 classes
			fillClasses(classPath, packageName, classFilter, classes);
		}

		//如果在项目的ClassPath中未找到，去系统定义的ClassPath里找
		if(classes.isEmpty()) {
			for (String classPath : getJavaClassPaths()) {
				logger.debug("Scan java classpath: [{"+classPath+"}]");
				// 填充 classes
				fillClasses(new File(classPath), packageName, classFilter, classes);
			}
		}
		return classes;
	}

	/**
	 * 获得ClassPath
	 * @param packageName 包名称
	 * @return
	 */
	public static Set<String> getClassPaths(String packageName){
		String packagePath = packageName.replace(StringUtils.DOT, StringUtils.SLASH);
		Enumeration<URL> resources;
		try {
			resources = Thread.currentThread().getContextClassLoader().getResources(packagePath);
		} catch (IOException e) {
			logger.error("Error when load classPath!", e);
			return null;
		}
		Set<String> paths = new HashSet<String>();
		while(resources.hasMoreElements()) {
			paths.add(resources.nextElement().getPath());
		}
		return paths;
	}

	/**
	 * 获得ClassPath
	 * 
	 * @return ClassPath
	 */
	public static String getClassPath() {
		return getClassPathURL().getPath();
	}

	/**
	 * 获得ClassPath URL
	 * @return ClassPath URL
	 */
	public static URL getClassPathURL() {
		return getURL(StringUtils.EMPTY);
	}

	/**
	 * 获得资源的URL
	 * @param resource 资源（相对Classpath的路径）
	 * @return 资源URL
	 */
	public static URL getURL(String resource) {
		return ClassUtils.getClassLoader().getResource(resource);
	}

	/**
	 * 改变 com -> com. 避免在比较的时候把比如 completeTestSuite.class类扫描进去，如果没有"."
	 * </br>那class里面com开头的class类也会被扫描进去,其实名称后面或前面需要一个 ".",来添加包的特征
	 * @param packageName
	 * @return
	 */
	private static String getWellFormedPackageName(String packageName) {
		return packageName.lastIndexOf(StringUtils.DOT) != packageName.length() - 1 ? packageName + StringUtils.DOT : packageName;
	}

	/**
	 * 获得Java ClassPath路径，不包括 jre<br>
	 * @return
	 */
	public static String[] getJavaClassPaths() {
		String[] classPaths = System.getProperty("java.class.path").split(System.getProperty("path.separator"));
		return classPaths;
	}

	/**
	 * 填充满足条件的class 填充到 classes<br>
	 * 同时会判断给定的路径是否为Jar包内的路径，如果是，则扫描此Jar包
	 * 
	 * @param path Class文件路径或者所在目录Jar包路径
	 * @param packageName 需要扫面的包名
	 * @param classFilter class过滤器
	 * @param classes List 集合
	 */
	private static void fillClasses(String path, String packageName, ClassFilter classFilter, Set<Class<?>> classes) {
		//判定给定的路径是否为
		int index = path.lastIndexOf(JAR_PATH_EXT);
		if(index != -1) {
			path = path.substring(0, index + JAR_FILE_EXT.length());
			path = StringUtils.removePrefix(path, PATH_FILE_PRE);
			processJarFile(new File(path), packageName, classFilter, classes);
		}else {
			fillClasses(new File(path), packageName, classFilter, classes);
		}
	}

	/**
	 * 填充满足条件的class 填充到 classes
	 * 
	 * @param file Class文件或者所在目录Jar包文件
	 * @param packageName 需要扫面的包名
	 * @param classFilter class过滤器
	 * @param classes List 集合
	 */
	private static void fillClasses(File file, String packageName, ClassFilter classFilter, Set<Class<?>> classes) {
		if (file.isDirectory()) {
			processDirectory(file, packageName, classFilter, classes);
		} else if (isClassFile(file)) {
			processClassFile(file, packageName, classFilter, classes);
		} else if (isJarFile(file)) {
			processJarFile(file, packageName, classFilter, classes);
		}
	}

	/**
	 * 处理如果为目录的情况,需要递归调用 fillClasses方法
	 * @param directory
	 * @param packageName
	 * @param classFilter
	 * @param classes
	 */
	private static void processDirectory(File directory, String packageName, ClassFilter classFilter, Set<Class<?>> classes) {
		for (File file : directory.listFiles(fileFilter)) {
			fillClasses(file, packageName, classFilter, classes);
		}
	}

	/**
	 * 处理为class文件的情况,填充满足条件的class 到 classes
	 * 
	 * @param file
	 * @param packageName
	 * @param classFilter
	 * @param classes
	 */
	private static void processClassFile(File file, String packageName, ClassFilter classFilter, Set<Class<?>> classes) {
		final String filePathWithDot = file.getAbsolutePath().replace(File.separator, StringUtils.DOT);
		int subIndex = -1;
		if ((subIndex = filePathWithDot.indexOf(packageName)) != -1) {
			final String className = filePathWithDot.substring(subIndex).replace(CLASS_FILE_SUFFIX, StringUtils.EMPTY);
			fillClass(className, packageName, classes, classFilter);
		}
	}

	/**
	 * 处理为jar文件的情况，填充满足条件的class 到 classes
	 * 
	 * @param file
	 * @param packageName
	 * @param classFilter
	 * @param classes
	 */
	private static void processJarFile(File file, String packageName, ClassFilter classFilter, Set<Class<?>> classes) {
		try {
			for (JarEntry entry : Collections.list(new JarFile(file).entries())) {
				if (isClass(entry.getName())) {
					final String className = entry.getName().replace(StringUtils.SLASH, StringUtils.DOT).replace(CLASS_FILE_SUFFIX, StringUtils.EMPTY);
					fillClass(className, packageName, classes, classFilter);
				}
			}
		} catch (Throwable ex) {
			logger.error(ex.getMessage(), ex);
		}
	}


	/**
	 * 实例化对象
	 * 
	 * @param clazz 类名
	 * @return 对象
	 * @throws Exception 
	 */
	@SuppressWarnings("unchecked")
	public static <T> T newInstance(String clazz) throws Exception {
		try {
			return (T) Class.forName(clazz).newInstance();
		} catch (Exception e) {
			throw new Exception(StringUtils.format("Instance class [{}] error!", clazz), e);
		}
	}

	/**
	 * 实例化对象
	 * 
	 * @param clazz 类
	 * @return 对象
	 * @throws Exception 
	 */
	public static <T> T newInstance(Class<T> clazz) throws Exception {
		try {
			return clazz.newInstance();
		} catch (Exception e) {
			throw new Exception(StringUtils.format("Instance class [{}] error!", clazz), e);
		}
	}

	/**
	 * 实例化对象
	 * @param clazz 类
	 * @return 对象
	 * @throws Exception 
	 */
	public static <T> T newInstance(Class<T> clazz, Object... params) throws Exception {
		if (CollectionUtils.isEmpty(params)) {
			return newInstance(clazz);
		}

		try {
			return clazz.getDeclaredConstructor(getClasses(params)).newInstance(params);
		} catch (Exception e) {
			throw new Exception(StringUtils.format("Instance class [{}] error!", clazz), e);
		}
	}

	/**
	 * 获得对象数组的类数组
	 * @param objects 对象数组
	 * @return 类数组
	 */
	public static Class<?>[] getClasses(Object... objects) {
		Class<?>[] classes = new Class<?>[objects.length];
		for (int i = 0; i < objects.length; i++) {
			classes[i] = objects[i].getClass();
		}
		return classes;
	}

	/**
	 * 指定类是否为Public
	 * 
	 * @param clazz 类
	 * @return 是否为public
	 */
	public static boolean isPublic(Class<?> clazz) {
		if (null == clazz) {
			throw new NullPointerException("Class to provided is null.");
		}
		return Modifier.isPublic(clazz.getModifiers());
	}

	/**
	 * 指定方法是否为Public
	 * 
	 * @param method 方法
	 * @return 是否为public
	 */
	public static boolean isPublic(Method method) {
		if (null == method) {
			throw new NullPointerException("Method to provided is null.");
		}
		return isPublic(method.getDeclaringClass());
	}


	/**
	 * 指定类是否为非public
	 * 
	 * @param clazz 类
	 * @return 是否为非public
	 */
	public static boolean isNotPublic(Class<?> clazz) {
		return false == isPublic(clazz);
	}

	/**
	 * 指定方法是否为非public
	 * 
	 * @param method 方法
	 * @return 是否为非public
	 */
	public static boolean isNotPublic(Method method) {
		return false == isPublic(method);
	}

	/**
	 * 是否为静态方法
	 * @param method 方法
	 * @return 是否为静态方法
	 */
	public static boolean isStatic(Method method){
		return Modifier.isStatic(method.getModifiers());
	}

	/**
	 * 设置方法为可访问
	 * @param method 方法
	 * @return 方法
	 */
	public static Method setAccessible(Method method) {
		if (null != method && ClassUtils.isNotPublic(method)) {
			method.setAccessible(true);
		}
		return method;
	}



	/**
	 * 加载类
	 * 
	 * @param <T>
	 * @param className 类名
	 * @param isInitialized 是否初始化
	 * @return 类
	 * @throws Exception 
	 */
	@SuppressWarnings("unchecked")
	public static <T> Class<T> loadClass(String className, boolean isInitialized) throws Exception {
		Class<T> clazz;
		try {
			clazz = (Class<T>) Class.forName(className, isInitialized, getClassLoader());
		} catch (ClassNotFoundException e) {
			throw new Exception(e);
		}
		return clazz;
	}

	/**
	 * 加载类并初始化
	 * @param <T>
	 * @param className 类名
	 * @return 类
	 * @throws Exception 
	 */
	public static <T> Class<T> loadClass(String className) throws Exception {
		return loadClass(className, true);
	}

	//---------------------------------------------------------------------------------------------------- Invoke end

	/**
	 * 查找指定对象中的所有方法（包括非public方法），也包括父对象和Object类的方法
	 * @param obj 被查找的对象
	 * @param methodName 方法名
	 * @param args 参数
	 * @return 方法
	 * @throws NoSuchMethodException 无此方法
	 * @throws SecurityException
	 */
	public static Method getDeclaredMethod(Object obj, String methodName, Object... args) throws NoSuchMethodException, SecurityException {
		return getDeclaredMethod(obj.getClass(), methodName, getClasses(args));
	}

	/**
	 * 查找指定类中的所有方法（包括非public方法），也包括父类和Object类的方法
	 * @param clazz 被查找的类
	 * @param methodName 方法名
	 * @param parameterTypes 参数类型
	 * @return 方法
	 * @throws NoSuchMethodException 无此方法
	 * @throws SecurityException
	 */
	public static Method getDeclaredMethod(Class<?> clazz, String methodName, Class<?>... parameterTypes) throws NoSuchMethodException, SecurityException {
		Method method = null;
		for (; clazz != Object.class; clazz = clazz.getSuperclass()) {
			try {
				method = clazz.getDeclaredMethod(methodName, parameterTypes);
				return method;
			} catch (NoSuchMethodException e) {
				//继续向上寻找
			}
		}
		return Object.class.getDeclaredMethod(methodName, parameterTypes);
	}

	/**
	 * 填充class 到 classes
	 * 
	 * @param className
	 * @param packageName
	 * @param classes
	 * @param classFilter
	 */
	private static void fillClass(String className, String packageName, Set<Class<?>> classes, ClassFilter classFilter) {
		if (className.startsWith(packageName)) {
			try {
				final Class<?> clazz = Class.forName(className, false, Thread.currentThread().getContextClassLoader());
				if (classFilter == NULL_CLASS_FILTER || classFilter.accept(clazz)) {
					classes.add(clazz);
				}
			} catch (Throwable ex) {
				logger.error("", ex);
			}
		}
	}

	private static boolean isClassFile(File file) {
		return isClass(file.getName());
	}

	private static boolean isClass(String fileName) {
		return fileName.endsWith(CLASS_FILE_SUFFIX);
	}

	private static boolean isJarFile(File file) {
		return file.getName().contains(JAR_FILE_EXT);
	}

	/**
	 * 类过滤器，用于过滤不需要加载的类
	 * @see http://www.oschina.net/code/snippet_234657_22722
	 */
	public interface ClassFilter {
		boolean accept(Class<?> clazz);
	}

	public static Class<?> getClass(Object object){
		boolean isCglibProxy = false;
		if(AopUtils.isCglibProxy(object)){
			isCglibProxy = true;
		}
		if(isCglibProxy || ClassUtils.isCglibProxy(object)){
			isCglibProxy = true;
		}
		Class<?> targetClass = object.getClass();
		if(isCglibProxy){
			targetClass =  targetClass.getSuperclass();
		}
		return targetClass;
	}

	public static String buildkey(Object object, Method method) {
		if (object != null) {
			return "";
		}
		return new StringBuilder(getClass(object).getName()).append(".").append(buildMethod(method)).toString();
	}

	public static String buildMethod(Method method){
		StringBuilder strbuilder = new StringBuilder(method.getName());
		Class<?>[] parameterTypes = method.getParameterTypes();
		if(parameterTypes != null && parameterTypes.length > 0){
			for(Class<?> parameterType : parameterTypes){
				strbuilder.append("#").append(parameterType.getName());
			}
		}
		return strbuilder.toString();
	}

}
